
mod asset_request_handler;
mod rpc_error;
mod jsonrpc_common;
mod service_router;


use crate::jsonrpc_common::{create_error_response_use_code, iterate_params, JsonRpcResponse};
use asset_request_handler::*;
use axum::extract::State;
use axum::{http::StatusCode, response::IntoResponse, routing::post, Json, Router};
use common_lib::ErrorCode::{CodeRpcInvalidArgument, CodeRpcServiceUnavailable, CodeRpcUnknownMethod};
use dotenvy::dotenv;
use jsonrpc_common::JsonRpcRequest;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;
use std::net::SocketAddr;
use std::ops::Deref;
use std::sync::Arc;
use tokio::net::TcpListener;
use tonic::transport::Channel;


#[derive(Clone)]
struct AppContext {
    pub router: service_router::Router,
}

#[tokio::main]
async fn main() {
    dotenv().ok();

    let addr_str = env::var("ADDR").unwrap();
    let mut context = Arc::new(AppContext {
        router: service_router::Router::new(),
    });
    // let logger = Arc::new(Logger::new());
    let app = Router::new()
        .route("/", post(handle_jsonrpc))
        // .route("/users/:id", get(get_user))
        // .route("/users", post(create_user))
        .with_state(context.clone());
        // .layer(Extension(logger));

    let addr:SocketAddr = addr_str.parse().unwrap();
    #[allow(rustdoc::http_links_are_not_secure)]
    println!("Server running on http://{}", addr);
    let listener = TcpListener::bind(addr).await.unwrap();
    axum::serve(listener, app)
        .await
        .unwrap();
}

fn create_response(status: StatusCode, response: JsonRpcResponse) -> impl IntoResponse {
    (status, Json(response))
}
async fn handle_jsonrpc(
    State(context): State<Arc<AppContext>>,
    Json(request): Json<JsonRpcRequest>,
) -> impl IntoResponse {
    let params = match request.params.as_ref() {
        Some(Value::Array(params))  => params,
        _ => return create_response(StatusCode::BAD_REQUEST, create_error_response_use_code(request.id.as_ref().unwrap().as_u64().unwrap(), &CodeRpcInvalidArgument)),
    };
    let _ = iterate_params(&request);
    let method_name = request.method.as_str();
    let r = &context.router;
    let service_name = r.route(method_name);
    if service_name.is_none() {
        return create_response(StatusCode::OK, create_error_response_use_code(request.id.as_ref().unwrap().as_u64().unwrap(), &CodeRpcServiceUnavailable));
    }
    let addr = service_name.unwrap();
    let endpoint = format!("http://{}", addr);
    let channel = Channel::from_shared(endpoint).unwrap()//Channel::from_static("http://[::1]:50051")
        .connect()
        .await.unwrap();

    let response = match request.method.as_str() {
        "asset.update"=> handle_asset_update(channel, params, &request.id.unwrap()).await,
        "asset.query"=> handle_asset_query(channel, params, &request.id.unwrap()).await,

        "test"=>handle_test(channel,params,&request.id.unwrap()).await,
        "add" => handle_add(request).await,
        _ => create_error_response_use_code(request.id.unwrap().as_u64().unwrap(), &CodeRpcUnknownMethod),
    };
    // todo 方法处理函数处理返回消息的公共代码移出到此
    // let message = response.unwrap().into_inner();
    // let result = serde_json::to_value(&message)
    //     .map_err(|e| return create_error_response_use_code(id.as_u64().unwrap(), &CodeRpcInternalError));
    //
    // JsonRpcResponse {
    //     jsonrpc: "2.0".to_string(),
    //     result: result.ok(),
    //     error: None,
    //     id: Some(id.clone()),
    // }

    // (StatusCode::OK, Json(response))
    create_response(StatusCode::OK, response)
}

// async fn handle_rpc_request(
//     request: JsonRpcRequest,
// ) -> Result<Value, rpc_error::RpcError> {
//     match request.method.as_str() {
//         "add" => {
//             let params = request.params.ok_or(RpcError::InvalidParams)?;
//             // 处理参数...
//             Ok(Value::Number(serde_json::Number::from(42)))
//         }
//         _ => Err(RpcError::MethodNotFound),
//     }
// }

